package drds.plus.sql_process.type;

import drds.plus.common.utils.convertor.Convertor;
import drds.plus.common.utils.convertor.ConvertorHelper;
import drds.plus.sql_process.abstract_syntax_tree.expression.NullValue;
import drds.plus.sql_process.optimizer.OptimizerException;

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;


public abstract class AbstractType<Value> implements Type<Value> {

    protected Class dataClass = null;

    public Class getValueClass() {
        if (dataClass == null) {
            java.lang.reflect.Type type = this.getClass().getGenericSuperclass();
            while (type != null && !(type instanceof ParameterizedType)) {
                type = ((Class) type).getGenericSuperclass();
            }

            if (type == null) {
                throw new OptimizerException("you should specify Type<Value> for Value type, ie: Type<String>");
            }
            dataClass = getGenericClass((ParameterizedType) type, 0);
        }

        return dataClass;
    }

    public Value convert(Object value) {
        if (value == null || value instanceof NullValue) {
            return null;
        } else {
            Convertor convertor = getConvertor(value.getClass());
            if (convertor != null) {
                // 没有convertor代表类型和目标相同，不需要做转化
                return (Value) convertor.convert(value, getValueClass());
            } else {
                return (Value) value;
            }
        }
    }

    /**
     * 获取convertor接口
     */
    protected Convertor getConvertor(Class clazz) {
        if (clazz.equals(getValueClass())) {
            return null;
        }

        Convertor convertor = ConvertorHelper.getInstance().getConvertor(clazz, getValueClass());
        if (convertor == null) {
            throw new RuntimeException("Unsupported convertByValueType: [" + clazz.getName() + "," + getValueClass().getName() + "]");
        } else {
            return convertor;
        }
    }

    /**
     * 取得范性信息
     */
    private Class<?> getGenericClass(ParameterizedType parameterizedType, int i) {
        Object genericClass = parameterizedType.getActualTypeArguments()[i];
        if (genericClass instanceof ParameterizedType) { // 处理多级泛型
            return (Class<?>) ((ParameterizedType) genericClass).getRawType();
        } else if (genericClass instanceof GenericArrayType) { // 处理数组泛型
            return (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType();
        } else {
            return (Class<?>) genericClass;
        }
    }
}
